#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
#include "shmem.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/msg.h>

union val_t {
    int b_val;
    int i_val;
    float f_val;
};
struct std_node
{
    int key;  //键值
    int type; //数据类型
    int dev_type;
    union val_t old_val;
    union val_t new_val;
    int ret;
};
struct msgbuf
{
    long type;
    int key;
    union val_t val;
};
int *n = NULL;
struct std_node *stu = NULL;

void cjson(char *buf)
{
    cJSON *root = cJSON_Parse(buf);
    cJSON *stm32 = cJSON_GetObjectItem(root, "stm32");
    cJSON *data = cJSON_GetObjectItem(stm32, "data");
    cJSON *arr = NULL;
    cJSON *val0 = NULL;
    cJSON *val1 = NULL;
    int a = cJSON_GetArraySize(data);
    stu = (struct std_node *)(n + 1);
    for (int i = 0; i < a; i++)
    {
        arr = cJSON_GetArrayItem(data, i);
        val0 = cJSON_GetObjectItem(arr, "name");
        val1 = cJSON_GetObjectItem(arr, "val");

        if (memcmp(val0->valuestring, "humi", 4) == 0)
        {
            stu->ret = -1;
            stu->old_val.i_val = stu->new_val.i_val;
            stu->new_val.i_val = val1->valueint;

            printf("上报完成:%d:%d:%d\n", stu->key, stu->new_val.i_val, stu->old_val.i_val);
        }
        if (memcmp(val0->valuestring, "temp", 4) == 0)
        {
            stu->ret = -1;
            stu->old_val.i_val = stu->new_val.i_val;
            stu->new_val.i_val = val1->valueint;
            printf("上报完成:%d:%d:%d\n", stu->key, stu->new_val.i_val, stu->old_val.i_val);
        }
        if (memcmp(val0->valuestring, "jiashi", 6) == 0)
        {
            stu->ret = -1;
            stu->old_val.b_val = stu->new_val.b_val;
            stu->new_val.b_val = val1->valueint;
            printf("上报完成:%d:%d:%d\n", stu->key, stu->new_val.b_val, stu->old_val.b_val);
        }
        if (memcmp(val0->valuestring, "jiare", 5) == 0)
        {
            stu->ret = -1;
            stu->old_val.b_val = stu->new_val.b_val;
            stu->new_val.b_val = val1->valueint;

            printf("上报完成:%d:%d:%d\n", stu->key, stu->new_val.b_val, stu->old_val.b_val);
        }
        if (memcmp(val0->valuestring, "fengji", 6) == 0)
        {
            stu->ret = -1;
            stu->old_val.b_val = stu->new_val.b_val;
            stu->new_val.b_val = val1->valueint;
            if (stu->type == 1)
                printf("上报完成:%d:%d:%d\n", stu->key, stu->new_val.b_val, stu->old_val.b_val);
            else if (stu->type == 2)
                printf("上报完成:%d:%d:%d\n", stu->key, stu->new_val.i_val, stu->old_val.i_val);
        }
        stu++;
    }
    stu = (struct std_node *)(n + 1);
    cJSON_Delete(root);
}
void *msgc(void *arg)
{
    int clientfd = *(int *)arg;
    printf("消息队列 = %d\n", clientfd);
    char name[16] = {0};
    char msg_buf[1024];
    int r;
    key_t key;
    int msgid;

    key = ftok("/mnt/msg.txt", 'b');
    if (key < 0)
    {
        perror("ftok err");
    }
    printf("key:%#x\n", key);

    //打开消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666);
        else
        {
            perror("msgget err");
        }
    }
    printf("msgid:%d\n", msgid);

    while (1)
    {
        //读消息对类并发送给stm32
        memset(msg_buf, 0, 1024);
        struct msgbuf msg;
        printf("send:\n");
        r = msgrcv(msgid, &msg, sizeof(msg) - sizeof(long), 20, 0);
        printf("end:\n");
        if (r > 0)
        {
            printf("接收消息成功:");
        }
        else
        {
            printf("接收失败\n");
        }
        memset(name, 0, 16);
        switch (msg.key)
        {
        case 303:
            strcpy(name, "jiashi");
            break;
        case 304:
            strcpy(name, "jiare");
            break;
        case 305:
            strcpy(name, "fengji");
            break;
        default:
            break;
        }
        cJSON *root = cJSON_CreateObject();
        cJSON *stm32 = cJSON_CreateObject();
        cJSON *data = cJSON_CreateArray();
        cJSON *arr = cJSON_CreateObject();
        cJSON_AddItemToObject(arr, "name", cJSON_CreateString(name));
        cJSON_AddItemToObject(arr, "val", cJSON_CreateNumber(msg.val.b_val));
        cJSON_AddItemToArray(data, arr);
        cJSON_AddItemToObject(stm32, "data", data);
        cJSON_AddItemToObject(root, "stm32", stm32);
        char *p = cJSON_PrintUnformatted(root);
        //printf("发送：%s\n", p);
        strcpy(msg_buf, p);
        send(clientfd, msg_buf, 1024, 0);
        printf("sand end:%s\n", msg_buf);
        cJSON_Delete(root);
        free(p);
    }
}
void *func(void *arg)
{
    int num = 0;
    char buf[KB];
    int ret;
    //这个clientfd属于线程栈资源，每个线程都有独立的空间
    int clientfd = *(int *)arg;
    printf("共享内存 = %d\n", clientfd);
    pthread_t tid;
    pthread_create(&tid, NULL, msgc, &clientfd);
    while (1)
    {    
        //接受stm32数据并上报共享内存
        memset(buf, 0, 1024);
        ret = recv(clientfd, buf, 1024, 0);
        if (ret > 0)
        {
            // printf("共享内存 %d\n", num);
        }
        else if (ret == 0) //对端发送完成并退出了
        {
            printf("client %d quit\n", clientfd);
            break;
        }
        else
        {
            perror("recv err");
        }
        if (memcmp(buf, "ASK", 3) == 0)
        {
            printf("ASK:%s\n", buf);
        }
        else
            cjson(buf);
    }

    close(clientfd);
}

int main(int argc, char const *argv[])
{
    //创建服务器的套接字
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd < 0)
    {
        perror("socket err");
        return -1;
    }
    //初始化服务器地址
    struct sockaddr_in server_addr, client_addr;
    int len = sizeof(server_addr);

    memset(&server_addr, 0, len);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8877);
    server_addr.sin_addr.s_addr = inet_addr("192.168.31.166");
    int yes = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
    {
        perror("setsockopt");
        // 错误处理
    }
    //绑定套接字的地址
    int ret = bind(server_fd, (struct sockaddr *)&server_addr, len);
    if (ret < 0)
    {
        perror("bind err");
        return -1;
    }

    //启动监听
    ret = listen(server_fd, 5);
    if (ret < 0)
    {
        perror("listen err");
        return -1;
    }

    struct shm_param para;

    shm_init(&para, "shm.txt", sizeof(stu));
    n = shm_getaddr(&para);
    while (1)
    {
        //接收连接
        printf("等待链接.....\n");
        int clientfd = accept(server_fd, (struct sockaddr *)&client_addr, &len);
        if (clientfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("链接成功\n");
        printf("main thread clientfd = %d\n", clientfd);

        //来一个链接，启动一个线程
        pthread_t tid;
        pthread_create(&tid, NULL, func, &clientfd);
    }
    shm_del(&para);
    close(server_fd);
    return 0;
}
